﻿using System;
using System.Threading;
using System.Windows.Input;
using Monti.Docking;
using Monti.MVVM;
using WikiUploader.Classes.MediaWikiAccess;

namespace WikiUploader.Classes
{
   /// <summary>
   /// Main view model
   /// </summary>
   public class MainViewModel : MainWindowViewModelBase
   {
      #region Fields

      private RelayCommand m_CmdLoginToWiki;
      private RelayCommand m_CmdEditPage;

      private DockGroup m_ActiveDockGroup;
      private DockItem m_ActiveContent;

      private string m_PageToOpen;
      private string m_UserName;
      private string m_Password;
      private string m_WikiSite;
      
      private bool m_IsSiteConnected;

      #endregion

      #region Setup

      /// <summary>
      /// Initializes a new main view model.
      /// </summary>
      public MainViewModel ()
      {
         DialogService.Instance.AddService (new MessageBoxDialogService ());
         SyncContex = SynchronizationContext.Current;
         var redirection = new ConsoleRedirection ();
         Console.SetOut (redirection);
         this.DockContent = new DockGroup ();
         var logGroup = new DockGroup {DockArea = DockArea.Bottom};
         var logViewModel = new LogViewModel ();
         logGroup.Items.Add (logViewModel);
         redirection.LineWritten += logViewModel.OnWriteLine;
         this.DockContent.Children.Add (logGroup);
         if (!Monti.Utilities.Common.IsInDesignMode)
            Settings = new Settings (this);
      }

      #endregion

      #region Command Properties

      /// <summary>
      /// Gets the login command.
      /// </summary>
      public ICommand LoginToWikiCommand
      {
         get { return this.m_CmdLoginToWiki ?? (this.m_CmdLoginToWiki = new RelayCommand (this.LoginToWiki, this.CanLoginToWiki)); }
      }

      /// <summary>
      /// Gets the go to page command.
      /// </summary>
      public ICommand EditPageCommand
      {
         get { return this.m_CmdEditPage ?? (this.m_CmdEditPage = new RelayCommand (this.EditPage, this.CanGoToPage)); }
      }

      #endregion

      #region Command Actions

      /// <summary>
      /// Logs into the wiki.
      /// </summary>
      /// <param name="obj">Command parameter.</param>
      private void LoginToWiki (object obj)
      {
         var login = new Action(this.LogIn);
         login.BeginInvoke (this.LoggedIn, null);
      }

      /// <summary>
      /// Checks if we can login to wiki or not.
      /// </summary>
      /// <param name="obj">Command parameter.</param>
      /// <returns>True if command can execute, otherwise false.</returns>
      private bool CanLoginToWiki (object obj)
      {
         return !this.IsSiteConnected && !string.IsNullOrEmpty (this.UserName) &&
            !string.IsNullOrEmpty (this.Password) && !string.IsNullOrEmpty (this.WikiSite);
      }

      /// <summary>
      /// Opens the <see cref="PageToOpen"/>.
      /// </summary>
      /// <param name="obj">Command parameter.</param>
      private void EditPage (object obj)
      {
         var editor = new WikiEditor (this.Site.GetPage(this.PageToOpen));
         this.ActiveDockGroup.Items.Add (editor);
      }

      /// <summary>
      /// Checks if we can go to a page or not.
      /// </summary>
      /// <param name="obj">Command parameter.</param>
      /// <returns>True if command can execute, otherwise false.</returns>
      private bool CanGoToPage (object obj)
      {
         return this.IsSiteConnected && !string.IsNullOrEmpty (this.PageToOpen);
      }

      #endregion

      #region Properties

      /// <summary>
      /// Gets or Sets the application settings.
      /// </summary>
      public static Settings Settings { get; private set; }

      /// <summary>
      /// Gets or Sets the wiki site.
      /// </summary>
      public MediaWikiSite Site { get; private set; }

      /// <summary>
      /// Gets the dock content.
      /// </summary>
      public DockGroup DockContent { get; private set; }

      /// <summary>
      /// Gets or Sets the Active dock group.
      /// </summary>
      public DockGroup ActiveDockGroup
      {
         get { return this.m_ActiveDockGroup; }
         set
         {
            this.m_ActiveDockGroup = value;
            this.RaisePropertyChanged ("ActiveDockGroup");
         }
      }

      /// <summary>
      /// Gets or Sets the Active dock content.
      /// </summary>
      public DockItem ActiveContent
      {
         get { return this.m_ActiveContent; }
         set
         {
            this.m_ActiveContent = value;
            this.RaisePropertyChanged ("ActiveContent");
         }
      }

      /// <summary>
      /// User name to login with.
      /// </summary>
      public string UserName
      {
         get { return this.m_UserName; }
         set
         {
            this.m_UserName = value;
            this.RaisePropertyChanged ("UserName");
         }
      }

      /// <summary>
      /// Gets or Sets the password.
      /// </summary>
      public string Password
      {
         get { return this.m_Password; }
         set
         {
            this.m_Password = value;
            this.RaisePropertyChanged ("Password");
         }
      }

      /// <summary>
      /// Gets or Sets if the site is connected or not.
      /// </summary>
      public bool IsSiteConnected
      {
         get { return this.m_IsSiteConnected; }
         private set
         {
            this.m_IsSiteConnected = value;
            this.RaisePropertyChanged ("IsSiteConnected");
         }
      }

      /// <summary>
      /// Gets or Sets the current wiki site.
      /// </summary>
      public string WikiSite
      {
         get { return this.m_WikiSite; }
         set
         {
            this.m_WikiSite = value;
            this.RaisePropertyChanged ("WikiSite");
         }
      }

      /// <summary>
      /// Gets or Sets the page to open.
      /// </summary>
      public string PageToOpen
      {
         get { return this.m_PageToOpen; }
         set
         {
            this.m_PageToOpen = value;
            this.RaisePropertyChanged ("PageToOpen");
         }
      }

      /// <summary>
      /// Gets the current SynchronizationContext.
      /// </summary>
      public static SynchronizationContext SyncContex { get; private set; }

      #endregion

      #region Methods

      /// <summary>
      /// Logs in to the wiki.
      /// </summary>
      private void LogIn ()
      {
         this.Site = new MediaWikiSite { WikiSiteUrl = this.WikiSite, UserName = this.UserName, UserPassword = this.Password };
         if (this.Site.Login ())
         {
            Settings.Save ();
            this.IsSiteConnected = true;
         }
      }

      /// <summary>
      /// Occurs after the log in.
      /// </summary>
      /// <param name="ar">IAsyncResult</param>
      private void LoggedIn (IAsyncResult ar)
      {
         if (this.IsSiteConnected)
         {
            SyncContex.Send (delegate
               {
                  //var editor = new WikiEditor (this.Site.GetPage ("Main Page"));
                  this.DockContent.Items.Add (new ExcerptUploaderModel (this.Site));
                  this.DockContent.Items.Add (new ExcerptUploaderModel (this.Site));
               }, null);
         }
      }

      /// <summary>
      /// Occurs when the application is closing.
      /// </summary>
      public void Closing ()
      {
         Settings.Save ();
      }

      #endregion
   }
}
